package com.future.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.db.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.future.allUtils.utils.CacheClient;
import com.future.allUtils.utils.SecurityUtils;
import com.future.domain.Announcement;
import com.future.domain.DTO.AnnouncementDTO;
import com.future.domain.Result;
import com.future.domain.User;
import com.future.mapper.AnnouncementMapper;
import com.future.mapper.UserMapper;
import com.future.service.AnnouncementService;
import com.future.service.NotificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class AnnouncementServiceImpl extends ServiceImpl<AnnouncementMapper, Announcement> implements AnnouncementService {


    @Autowired
    private AnnouncementMapper announcementMapper;
    @Autowired
    private CacheClient cacheClient;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private NotificationService notificationService;
    @Override
    @Transactional
    public Result publishAnnouncement(AnnouncementDTO announcementDTO){
        Announcement announcement = new Announcement();
        // 校验标题和内容非空
        if (StringUtils.isEmpty(announcementDTO.getTitle()) || announcementDTO.getTitle().trim().isEmpty()) {
            return Result.fail("公告标题不能为空");
        }
        if (StringUtils.isEmpty(announcementDTO.getContent()) || announcementDTO.getContent().trim().isEmpty()) {
            return Result.fail("公告内容不能为空");
        }
        if (announcementDTO.getIsPinned() != 0 && announcementDTO.getIsPinned() != 1) {
            return Result.fail("置顶状态必须为0或1");
        }

        Long publisherId;
        try {
            publisherId = SecurityUtils.getCurrentUserId(); // 核心：从Security上下文获取发布者ID
        } catch (RuntimeException e) {
            return Result.fail("请先登录"); // 用户未登录时返回错误
        }
        BeanUtil.copyProperties(announcementDTO,announcement);
        announcement.setPublishedAt(LocalDateTime.now());
        announcement.setPublisherId(publisherId);
        announcement.setIsPinned(announcementDTO.getIsPinned());
        int success =announcementMapper.insert(announcement);
        if(success>0) {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(User::getId);
            List<User> users = userMapper.selectList(queryWrapper);
            List<Long>usersId=users.stream().map(User::getId).collect(Collectors.toList());
            String content=announcement.getTitle()+"；"+announcement.getContent();
            notificationService.sendAnnouncement(announcement.getId(),content,usersId);
        }
        return success>0? Result.ok("公告发布成功") : Result.fail("公告发布失败");
    }

    @Override
    public Result getAnnouncements(IPage<Announcement> page) {
        // 1. 校验分页参数（默认值处理）
        long pageNum = page.getCurrent();
        long pageSize = page.getSize();

        // 2. 构建缓存key
        String cacheKey = "announcement:page:" + pageNum + ":size:" + pageSize;

        // 3. 查询缓存
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult; // 缓存命中直接返回
        }

        // 4. 缓存未命中：执行数据库分页查询
        LambdaQueryWrapper<Announcement> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Announcement::getPublishedAt); // 按创建时间倒序

        IPage<Announcement> resultPage = announcementMapper.selectPage(page, queryWrapper);

        // 5. 结果存入Redis
        Result result = Result.ok(resultPage); // 直接封装IPage对象（包含records和total）
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        return result;
    }
    @Override
    public Result getAnnouncementById(Long id) {
        // 1. 校验ID有效性
        if (id == null || id <= 0) {
            return Result.fail("公告ID无效");
        }

        // 2. 构建缓存键
        String cacheKey = "announcement:id:" + id;

        // 3. 查询缓存（复用缓存穿透解决方案，自动处理缓存未命中逻辑）
        Announcement announcement = cacheClient.queryWithPassThrough(
                cacheKey,  // 缓存键
                id,        // 查询参数（公告ID）
                Announcement.class,  // 返回类型
                (announcementId) -> announcementMapper.selectById(announcementId),  // 缓存未命中时执行数据库查询
                30L,       // 缓存时效（30分钟，参考文章缓存策略）
                TimeUnit.MINUTES
        );

        // 4. 处理查询结果（区分"缓存空值"和"数据不存在"）
        if (announcement == null) {
            return Result.fail("公告不存在或已删除");
        }
        return Result.ok(announcement);
    }

    @Override
    public Result getAnnouncementsByName(IPage<Announcement> page, String name) {
        // 1. 校验查询参数
        if (StringUtils.isEmpty(name)) {
            return Result.fail("名称关键词不能为空");
        }

        // 2. 构建缓存key（包含查询关键词和分页参数，确保唯一性）
        long pageNum = page.getCurrent();
        long pageSize = page.getSize();
        String cacheKey = "announcement:name:" + name + ":page:" + pageNum + ":size:" + pageSize;

        // 3. 查询缓存
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult;
        }

        // 4. 缓存未命中：执行数据库查询（模糊匹配标题，按创建时间倒序）
        LambdaQueryWrapper<Announcement> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Announcement::getTitle, name)  // 模糊查询标题
                .orderByDesc(Announcement::getPublishedAt);  // 最新公告优先

        IPage<Announcement> resultPage = announcementMapper.selectPage(page, queryWrapper);

        // 5. 结果存入缓存（30分钟逻辑过期）
        Result result = Result.ok(resultPage);
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        return result;
    }

    @Override
    public Result top(Long id) {
        Announcement announcement = announcementMapper.selectById(id);
        if (announcement == null) {
            return Result.fail("公告不存在");
        }
        announcement.setIsPinned(1);
        int success = announcementMapper.updateById(announcement);
        cacheClient.deleteByPattern("announcement:*");
        return success > 0 ? Result.ok("公告置顶成功") : Result.fail("公告置顶失败");
    }

    @Override
    public Result cancelTop(Long id) {
        Announcement announcement = announcementMapper.selectById(id);
        if (announcement == null) {
            return Result.fail("公告不存在");
        }
        announcement.setIsPinned(0);
        int success = announcementMapper.updateById(announcement);
        cacheClient.deleteByPattern("announcement:*");
        return success > 0 ? Result.ok("取消置顶成功") : Result.fail("取消置顶失败");
    }

    @Override
    public Result getLatestAnnouncement() {
        // 1. 构建缓存key（单条最新公告专用key）
        String cacheKey = "announcement:latest:top1";

        // 2. 查询缓存（复用逻辑过期策略）
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> getLatestAnnouncementFromDb(), 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult; // 缓存命中直接返回
        }

        // 3. 缓存未命中：执行数据库查询（最新1条）
        Result announcement = getLatestAnnouncementFromDb();
        if (announcement.getData() == null) {
            return Result.fail("暂无最新公告");
        }

        // 4. 结果存入Redis（逻辑过期）
        Result result = Result.ok(announcement.getData());
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        return result;
    }

    // 数据库查询实现
    private Result getLatestAnnouncementFromDb() {
        LambdaQueryWrapper<Announcement> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Announcement::getPublishedAt) // 按发布时间倒序
                .last("LIMIT 1"); // 限制查询1条记录
        return Result.ok(announcementMapper.selectOne(queryWrapper));
    }

    @Override
    public Result getPinnedAnnouncements() {
        // 1. 构建缓存key
        String cacheKey = "announcement:pinned";

        // 2. 查询缓存
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> getPinnedAnnouncementsFromDb(), 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult;
        }

        // 3. 缓存未命中：执行数据库查询
        Result pinnedAnnouncements = getPinnedAnnouncementsFromDb();
        if (pinnedAnnouncements.getData() == null) {
            return Result.fail("暂无置顶公告");
        }

        // 4. 结果存入Redis（逻辑过期）
        Result result = Result.ok(pinnedAnnouncements.getData());
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        return result;
    }

    // 数据库查询实现：获取所有置顶公告
    private Result getPinnedAnnouncementsFromDb() {
        LambdaQueryWrapper<Announcement> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Announcement::getIsPinned, 1) // 筛选置顶状态为1的公告
                .orderByDesc(Announcement::getPublishedAt); // 按发布时间倒序
        return Result.ok(announcementMapper.selectList(queryWrapper));
    }

}
